#include <cstdio>    // 文件操作：C语言IO标准库 freopen fopen fclose fscanf fprintf
#include <fstream>   // 文件输入输出流 ifstream ofstream
#include <iostream>  // 标准输入输出流 cin cout
using namespace std;

// 文件：数据存储的载体
// - 编码格式：ASCLL、UTF-8、GBK、GB2312
// - 二进制文件：.exe
// - 图片文件：.jpg .png .gif
// - 音频文件：.mp3 .wav
// - 视频文件：.mp4 .avi
// - 文本和文档：.txt .md .docx .pdf

/** 文件操作：freopen fclose fopen fscanf fprintf ifstream ofstream
 * @fn freopen 文件重定向
 * 原理：改变输入输出流，将原本的标准输入输出流（stdin stdout 从键盘接收）重定向指定的文件流
 * @param filename 文件名 string/char* 类型
 * @param mode 文件打开方式 string/char* 类型：
 * - "r" ：只读 打开一个待读取文件，若不存在则返回空指针
 * - "w" ：只写 创建一个用于写入的空文件，若文件已存在则用新文件覆盖
 * - "a" ：追加 在文件末尾写入数据，若不存在则新建
 * - "r+"：读写 打开一个待更新文件，若不存在则返回空指针
 * - "w+"：读写 创建一个用于写入和读取的空文件，若文件已存在则用新文件覆盖
 * - "a+"：读追 打开一个用于读取和追加的文件，若不存在则新建
 * @param stream 文件指针 file* 类型 stdin stdout
 *
 * @fn fclose 关闭文件
 * @param stream 文件指针 file* 类型 stdin stdout
 *
 * @fn fopen 打开文件
 * @param filename 文件名 string/char* 类型
 * @param mode 文件打开方式 string/char* 类型
 * - "r"	打开一个用于读取的文件。该文件必须存在。
 * - "w"	创建一个用于写入的空文件。如果文件名称与已存在的文件相同，则会删除已有文件的内容，文件被视为一个新的空文件。
 * - "a"	追加到一个文件。写操作向文件末尾追加数据。如果文件不存在，则创建文件。
 * - "r+"	打开一个用于更新的文件，可读取也可写入。该文件必须存在。
 * - "w+"	创建一个用于读写的空文件。
 * - "a+"	打开一个用于读取和追加的文件。
 * @fn fscanf
 * @param stream 文件指针 file* 类型 stdin stdout
 * @param format 格式字符串
 * @param
 *
 * @fn fprintf
 * @param stream 文件指针 file* 类型 stdin stdout
 * @param format 格式字符串
 * @param
 */

// 例一：累加求和 使用文件重定向 freopen
void eg1() {
  // 从 in.txt 中读取数据（内容为三个整数）
  // 输出它们的和并保存到 out.txt 文件中
  // 读文件：
  // 只读方式打开 in.txt 文件，
  // 打开成功返回文件指针
  // 打开失败返回空指针 NULL
  freopen("in.txt", "r", stdin);
  // 写文件：把内容输出到文件中
  // 将标准输出流 stdout 重定向到 out.txt 文件
  freopen("out.txt", "w", stdout);
  int temp, sum = 0;
  // 循环读取数据，读完（读到文件结束标志 EOF，类似 string 的 '\0'）终止循环
  // scanf("%d", &temp) == 1
  while (cin >> temp) {
    sum += temp;
  }
  // printf("%d", sum);
  cout << sum << endl;
  // 关闭输入文件
  fclose(stdin);
  // 关闭输出文件
  fclose(stdout);
}
// 例二：累加求和2 使用文件指针 fopen
void eg2() {
  FILE *fin, *fout;               // 定义文件指针
  fin = fopen("in.txt", "rb");    // 输入指针赋值
  fout = fopen("out.txt", "wb");  // 输出指针赋值
  int temp, sum = 0;
  // 循环读取数据，读完（读到文件结束标志 EOF，类似 string 的 '\0'）终止循环
  // 格式化输入 fscanf(fin, "%d", &temp)
  while (fscanf(fin, "%d", &temp) != EOF) {
    sum += temp;
  }
  fprintf(fout, "%d\n", sum);  // 格式化输出
  fclose(fin);                 // 关闭输入流
  fclose(fout);                // 关闭输出流
}
// 总结：
// 重定向 freopen 使用更方便，但有的竞赛不允许读取文件甚至允许读取却不允许使用，且不能同时使用读写文件和输入输出
// 文件指针 fopen 使用更通用，但需要定义和维护文件指针

// 全局声明输入输出对象
// ifstream fin("in.txt");
// ofstream fout("out.txt");
// 若想将 fin fout 处替换为 cin cout 功能
// 不用将所有地方替换，只需去掉上述声明并添加如下两行（宏定义）
// #define fin cin
// #define fout cout
// 虽然可以节省时间，但不推荐将这种做法应用到工作和开发中

// 例三：对角线求和 使用输入输出对象 ifstream ofstream
// 解题思路：
// 1. 创建二维数组（矩阵）
// 2. 读取文件数据，初始化矩阵，关闭文件
// 3. 定义累加变量，遍历矩阵对角线
// 4. 输出结果
// - 输入矩阵为正方形矩阵（方阵）
// int main
void eg3() {
  const int SIZE = 4;       // 定义常量：矩阵大小
  int matrix[SIZE][SIZE];   // 声明矩阵
  ifstream fin("eg3.txt");  // 创建输入对象，int float
  ofstream fout("eg3-out.txt");
  // 类和对象，ifstream 类（对象的模板） => 创建了一个输入文件对象 （类的实例）
  // 给矩阵赋初值
  for (int i = 0; i < SIZE; i++) {
    for (int j = 0; j < SIZE; j++) {
      fin >> matrix[i][j];  // 输入数据：数据来源 eg3.txt
    }
  }
  fin.close();  // 关闭输入文件
  // 主对角线 suma，副对角线 sumb
  int suma = 0, sumb = 0;
  // 遍历主对角线
  for (int i = 0; i < SIZE; i++) {
    suma += matrix[i][i];
  }
  // 遍历副对角线
  for (int i = 0; i < SIZE; i++) {
    sumb += matrix[i][SIZE - i - 1];
  }
  fout << "主对角线求和：" << suma << "\n"
       << "副对角线求和：" << sumb << endl;
}

// 例四：杨辉三角 从 1 开始，当前位置数值等于左上角数+正上方数
// 解题思路：
// 1. 读文件，获取杨辉三角行数
// 2. 创建并根据定义初始化矩阵
// 3. 遍历矩阵三角，输出矩阵
void eg4() {
  int n;
  ifstream fin("eg4-in.txt");
  fin >> n;
  int matrix[n][n] = {{0}};
  for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) {
      if (j == 0 || j == i) {
        matrix[i][j] = 1;
      } else {
        matrix[i][j] = matrix[i - 1][j - 1] + matrix[i - 1][j];
      }
    }
  }
  fin.close();
  ofstream fout("eg4-out.txt");
  for (int i = 0; i < n; i++) {
    for (int j = 0; j <= i; j++) {
      fout << matrix[i][j] << " ";
    }
    fout << '\n';
  }
  fout.close();
}

void test() {
  ifstream fin("test.txt");
  char temp;
  while (fin >> temp) {
    cout << temp;
  }
}
int main() {
  // 设置控制台代码页字符集为 UTF-8 防止中文乱码
  system("chcp 65001>nul");
  // test();
  eg1();
  return 0;
}